package com.hs.sharding.algorithm;

import com.google.common.collect.Range;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingValue;
import org.apache.shardingsphere.sharding.exception.syntax.UnsupportedShardingOperationException;

import java.util.*;

/**
 * 实现自定义COMPLEX分片策略
 * 声明算法时，ComplexKeysShardingAlgorithm接口可传入一个泛型，这个泛型就是分片键的数据类型。
 * 这个泛型只要实现了Comparable接口即可。
 * 但是官方不建议声明一个明确的泛型出来，建议是在doSharding中再做类型转换。这样是为了防止分片键类型与算法声明的类型不符合。
 * <p>
 * 我此时uid就是long   status是int   我进行测试
 *
 * @auth roykingw
 */
public class MyComplexAlgorithm implements ComplexKeysShardingAlgorithm<Long> {

    private Properties props;

    @Override
    public Collection<String> doSharding(Collection<String> collection, ComplexKeysShardingValue<Long> complexKeysShardingValue) {
        // 假如此时SQL为 select * from sys_user where uid in (xxx,xxx,xxx) and status between {lowerEndpoint} and {upperEndpoint};
        Collection<Long> uidList = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get("uid");
        Range<Long> status = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("status");

        // 拿到status的查询范围
        if (status != null) {
            Long lowerEndpoint = status.lowerEndpoint();
            Long upperEndpoint = status.upperEndpoint();
            if (lowerEndpoint > upperEndpoint) {
                // 如果下限 > 上限  抛出异常，终止去数据库查询的操作
                throw new UnsupportedShardingOperationException("empty record query", "sys_user");
            } else if (lowerEndpoint < 0 || upperEndpoint > 1) {
                // 如果查询范围明显不在status字段的区间中
                //抛出异常，终止去数据库查询的操作
                throw new UnsupportedShardingOperationException("error range query param", "sys_user");
            }
        }

        // 校验都通过后，就按照自定义的分片规则来进行分片，我这里就按照uid的奇偶来进行
        List<String> result = new ArrayList<>();
        // 获取逻辑表名 sys_user   而我们的真实表为sys_user1  sys_user2
        String logicTableName = complexKeysShardingValue.getLogicTableName();
        for (Long uid : uidList) {
            String resultTableName = logicTableName + ((uid + 1) % 4 /2 + 1);
            if (!result.contains(resultTableName)) {
                result.add(resultTableName);
            }

        }
        return result;
    }

    @Override
    public Properties getProps() {
        return props;
    }

    @Override
    public void init(Properties properties) {
        this.props = props;
    }

}
